#include "XnccAddress.h"
#include <memory>
#include <netinet/in.h>
#include "IpV4Address.h"
#include "IpV6Address.h"
#include "UnixDomainAddress.h"
#include "Util.h"

namespace xncc {
namespace foundation {
    using namespace shared;
    namespace {
        constexpr char TCP_COMM_TYPE[]                = "tcp";
        constexpr char UDP_COMM_TYPE[]                = "udp";
        constexpr char UNIX_DOMAIN_SOCKET_COMM_TYPE[] = "uds";
        constexpr char SHARED_MEMORY_COMM_TYPE[]      = "shm";
    }  // namespace

    std::shared_ptr<XnccAddress> XnccAddress::CreateAddress(const std::string& addr)
    {
        /// tcp@127.0.0.1:9000
        /// uds@path
        /// udp@127.0.0.1:9000
        /// shm@path
        auto typePos = addr.find_first_of('@');
        if (typePos == std::string::npos) {
            throw logic_exception(std::string("is not valid addr "));
        }
        const std::string typeStr = addr.substr(0, typePos);
        const std::string dataStr = addr.substr(typePos + 1);

        if (typeStr == TCP_COMM_TYPE) {
            auto pos = dataStr.find_last_of(':');
            if (pos == std::string::npos) {
                throw logic_exception(std::string("is not valid ip addr "));
            }
            std::string ipStr = dataStr.substr(0, pos);
            if (CommonBusi::isIpV6(ipStr)) {
                return std::make_shared<IpV6Address>(dataStr);
            }
            if (CommonBusi::isIpV4(ipStr)) {
                return std::make_shared<IpV4Address>(dataStr);
            }
            throw logic_exception("is not valid ip addr ");
        }
        if (typeStr == UNIX_DOMAIN_SOCKET_COMM_TYPE) {
            return std::make_shared<UnixDomainAddress>(dataStr);
        }
        if (typeStr == UDP_COMM_TYPE) {
            auto pos = dataStr.find_last_of(':');
            if (pos == std::string::npos) {
                throw logic_exception(std::string("is not valid ip addr "));
            }
            std::string ipStr = dataStr.substr(0, pos);
            if (CommonBusi::isIpV6(ipStr)) {
                return std::make_shared<IpV6Address>(dataStr, IPPROTO_UDP);
            }
            if (CommonBusi::isIpV4(ipStr)) {
                return std::make_shared<IpV4Address>(dataStr, IPPROTO_UDP);
            }
            throw logic_exception("is not valid ip addr ");
        }
        if (typeStr == SHARED_MEMORY_COMM_TYPE) {  // 共享内存通信
            throw logic_exception("unsupported addr format, comming soon");
        }
        throw logic_exception("error addr format");

        return nullptr;
    }
}  // namespace foundation
}  // namespace xncc